Conversation
Add three new request-body knobs (all default false β zero behavior change): - deny_selinux_disable: blocks label=disable / label:disable SecurityOpt - deny_selinux_label_override: blocks label=user:/role:/type:/level: overrides - deny_unconfined_system_paths: blocks systempaths=unconfined SecurityOpt AND empty MaskedPaths/ReadonlyPaths arrays (direct-API bypass vector) Wires the new fields through config.go, load.go SetDefaults, and filter_options.go. Adds MaskedPaths/ReadonlyPaths *[]string pointer fields to the container create wire type so nil (absent) and non-nil empty (unconfined) are distinguishable. Covers all paths with table-driven unit tests, env-var round-trip tests, config mapping tests, and fuzz seeds exercised against both a permissive and a strict policy instance.
Add three opt-in knobs to request_body.service that gate swarm service create/update on ContainerSpec.Privileges.Seccomp.Mode and AppArmor.Mode: - deny_unconfined_seccomp: denies Mode=="unconfined" (EqualFold) - deny_custom_seccomp_profiles: denies Mode=="custom" and also a Seccomp object with empty Mode but non-empty Profile blob (fail-closed) - deny_unconfined_apparmor: denies AppArmor.Mode=="disabled" All three default false (opt-in). Extends serviceContainerPrivileges with Seccomp and AppArmor sub-structs decoded from the wire JSON. Adds three SetDefault registrations in load.go so SOCKGUARD_* env vars are not silently dropped by Viper. Maps all three fields in filter_options.go. New tests: TestServiceInspectDenyUnconfinedSeccomp (7 cases), TestServiceInspectDenyCustomSeccompProfiles (7 cases including Profile-without-Mode fail-closed), TestServiceInspectDenyUnconfinedAppArmor (6 cases), TestServiceInspectSeccompAndAppArmorRailsCompose, TestServiceInspectSeccompDenialOnUpdatePath, TestLoadHonorsServiceSeccompAppArmorEnvVars.
When hot reload drops a profile that had a concurrency cap, its sockguard_inflight_requests series now disappears from the next scrape rather than persisting at a stale value. - Add Registry.DeleteInflightProfile to remove the in-flight gauge series for a named profile from the sync.Map exposition. - In reloadCoordinator.reload, capture the old concurrency-capped profile set before activeCfg advances, swap the handler, then delete series for profiles absent from the new config (after Swap so new requests are already on the new chain). - Add profileNamesWithConcurrency and removedProfiles helpers. - Tests: series-absent-after-delete, sequential-recreate-at-zero, nil-safety, concurrent hammer under -race, coordinator integration (profile removed and profile retained across reload).
Replace atomic.Pointer[bucketState] with a single atomic.Uint64 that packs the 16.16 fixed-point token count (bits [31:0]) and millisecond timestamp mod 2^32 (bits [63:32]) into one word. Every admitted request previously allocated a 16-byte bucketState heap object; the CAS now stores directly into the uint64. Denied requests were already allocation-free; both branches are now 0 allocs/op. Before: BenchmarkLimiterAllowNHot β 47 ns/op, 16 B/op, 1 allocs/op After: BenchmarkLimiterAllowNHot β 36 ns/op, 0 B/op, 0 allocs/op New: BenchmarkBucket_AllowNPacked β 34 ns/op, 0 B/op, 0 allocs/op Behavioral change: refill granularity drops from nanosecond to millisecond precision. Sub-ms calls see elapsedMS=0 and skip refill. For all supported rates (max 65535 t/s = ~1 token/15Β΅s), this is negligible; documented in the bucket struct comment. Config change: limits.rate.burst (and tokens_per_second, since burst >= tps) is now capped at 65535 by the validator. The 16-bit integer part of the packed token field overflows at 65536. Enforced at startup; no operator config in the repo uses values near this bound.
β¦ceiling The 1e9 'effectively unlimited' sentinels truncate in the 16.16 fixed-point encoding (uint32(1e9*65536) wraps), silently corrupting token counts, so the Limiter benchmarks now use MaxPackedBurst (65535). Benchmark comments now state honestly that drained-bucket iterations measure the deny branch.
β¦confinement modes, gauge cleanup, packed bucket - π docs(config): SELinux label= / systempaths= knobs β example YAML, prose, knob table, env-var rows - π docs(config): service seccomp/AppArmor confinement-mode knobs β same four touchpoints - π docs(config): limits.rate.burst 65535 upper bound (packed token-field limit) - π docs(changelog): Added/Fixed/Changed entries for all four items - π docs(readme): roadmap β confinement parity, SecurityOpt evaluation, gauge cleanup, and alloc-free bucket marked shipped
β¦ branches During an rc soak, feature work lands on dev/vX.Y instead of main, but ci-verify's pull_request trigger only covered main β dev-targeted PRs got just the integration job and external checks. dev branches are the next release line and deserve the same gate.
β¨ v1.4 roadmap batch: SecurityOpt SELinux/systempaths, swarm confinement modes, gauge cleanup, alloc-free rate-limit bucket
Bumps the go-minor group in /app with 1 update: [github.com/sigstore/sigstore-go](https://github.com/sigstore/sigstore-go). Updates `github.com/sigstore/sigstore-go` from 1.1.4 to 1.2.0 - [Release notes](https://github.com/sigstore/sigstore-go/releases) - [Commits](sigstore/sigstore-go@v1.1.4...v1.2.0) --- updated-dependencies: - dependency-name: github.com/sigstore/sigstore-go dependency-version: 1.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the actions-minor group with 1 update in the / directory: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 4.36.1 to 4.36.2 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@87557b9...8aad20d) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the npm-minor group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) | `6.15.0` | `6.16.1` | | [turbo](https://github.com/vercel/turborepo) | `2.9.16` | `2.9.17` | | [next](https://github.com/vercel/next.js) | `16.2.7` | `16.2.9` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.9.1` | `25.9.2` | | [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.16` | `19.2.17` | | [fumadocs-mdx](https://github.com/fuma-nama/fumadocs) | `15.0.10` | `15.0.11` | | [@types/mdx](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mdx) | `2.0.13` | `2.0.14` | Updates `knip` from 6.15.0 to 6.16.1 - [Release notes](https://github.com/webpro-nl/knip/releases) - [Commits](https://github.com/webpro-nl/knip/commits/knip@6.16.1/packages/knip) Updates `turbo` from 2.9.16 to 2.9.17 - [Release notes](https://github.com/vercel/turborepo/releases) - [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md) - [Commits](vercel/turborepo@v2.9.16...v2.9.17) Updates `next` from 16.2.7 to 16.2.9 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](vercel/next.js@v16.2.7...v16.2.9) Updates `@types/node` from 25.9.1 to 25.9.2 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@types/react` from 19.2.16 to 19.2.17 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) Updates `fumadocs-mdx` from 15.0.10 to 15.0.11 - [Release notes](https://github.com/fuma-nama/fumadocs/releases) - [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs-mdx@15.0.10...fumadocs-mdx@15.0.11) Updates `@types/mdx` from 2.0.13 to 2.0.14 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/mdx) --- updated-dependencies: - dependency-name: knip dependency-version: 6.16.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor - dependency-name: turbo dependency-version: 2.9.17 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: next dependency-version: 16.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: "@types/node" dependency-version: 25.9.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: "@types/react" dependency-version: 19.2.17 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: fumadocs-mdx dependency-version: 15.0.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: "@types/mdx" dependency-version: 2.0.14 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor ... Signed-off-by: dependabot[bot] <support@github.com>
β¦+ lockfile regen The root overrides pinning next's nested postcss to ^8.5.14 were never actually applied: the override spec must exactly match the workspaces' direct dependency spec (^8.5.15), and the stale resolution survived in package-lock.json/node_modules through incremental installs. Aligning the spec and regenerating the lockfile from a clean tree drops the last postcss@8.4.31 (SNYK-JS-POSTCSS-16189065, medium XSS); snyk test is now clean across all projects.
β¦s for standalone resolvers Snyk's SCM PR check resolves each changed manifest in isolation, where root-level npm overrides are invisible β docs/package.json and website/package.json standalone still resolved next's nested postcss@8.4.31 (SNYK-JS-POSTCSS-16189065) even though the installed workspace tree is clean. Mirroring the override into both workspace manifests fixes the standalone view; npm ignores non-root overrides in the real workspace install, so package-lock.json is unchanged.
β¦never installed) Snyk's PR check resolves workspace manifests standalone, without root lockfile or npm-overrides context, and does not apply the overrides declared in the manifests themselves β so it keeps reporting next's pinned postcss@8.4.31 even though the installed tree and lockfile only ever contain >=8.5.15. Time-boxed ignore (expires 2026-09-15) at root plus per-workspace mirrors, since manifest-only projects read policy from the manifest's directory.
π¦ deps: batch Dependabot minors β sigstore-go 1.2.0, codeql-action 4.36.2, npm-minor group
# Conflicts: # CHANGELOG.md
Adds app/configs/lookout.yaml β a first-class sockguard preset for the lookout Docker agent. Derived from the drydock preset: same rule surface (container list/inspect/stats/lifecycle/create, image pull/inspect/remove, events, narrow network/volume/distribution/service reads) with redaction posture matched to the drydock passthrough topology (redact_mount_paths=false, redact_container_env=false, redact_network_topology=false). Includes allowed_runtimes: [runc] to prevent 403s when lookout recreates containers from inspect specs. Header comments document when standalone operators should re-enable redactions and how to switch to lookout-with-exec.yaml for exec support. Also adds examples/compose/lookout/ following the existing compose-example convention: sockguard + lookout services sharing a named-volume unix socket, self-contained sockguard.yaml (copy of the preset), and a README covering audience, security tradeoffs, and the redaction note.
Extends lookout.yaml with exec support for interactive terminal access
through the lookout agent (e.g. terminal-over-websocket or drydock-driven
exec sessions in lookout's edge mode).
Adds rules for POST /containers/{id}/exec, POST /exec/{id}/start,
POST /exec/{id}/resize, and GET /exec/{id}/json following the exec-enabled
preset pattern (github-actions-runner.yaml syntax). Body inspection:
allow_privileged=false, allow_root_user=true for interactive sessions.
Header comments document when to use this preset vs. lookout.yaml (exec
disabled baseline) and when to use allowed_commands instead for pinned
argv use cases.
Extends drydock.yaml with the exec paths required for drydock's self-update
finalize flow. The flow (SelfUpdateController.runFinalizeCallbackInContainer)
uses POST /containers/{id}/exec to create an exec instance, POST /exec/{id}/start
to run it (Detach:false, Tty:false), and GET /exec/{id}/json to confirm the
exit code.
The exec body inspection uses allowed_commands to pin the permitted argv to
the single finalize entrypoint β any other exec call is denied at the body
inspection layer even though the rule allows POST /containers/*/exec.
allow_privileged=false, allow_root_user=false (drydock images run as nonroot).
Header comment documents the full self-update exec flow with source references,
the security tradeoff (narrower exec surface vs. full self-update support),
and the allowed_bind_mounts requirement for the helper container's socket bind.
β¦lfupdate Updates all three registration touchpoints identified in the recon map: README.md: - Recent updates bullet: 12 β 15, enumerate lookout + lookout-with-exec + drydock-with-selfupdate - Features table YAML Configuration cell: 12 β 15, add lookout to examples - Bundled presets (12) β (15) heading + dot-separated link list: add three new preset links - Ready-to-run compose examples: add lookout link docs/content/docs/presets.mdx: - description frontmatter: add all three new preset names - Add four new H2 sections following the existing pattern: Drydock with Self-Update, Lookout, Lookout with Exec
β¦ lookout preset
lookout's GetContainerLogs() calls GET /containers/{id}/logs (including
follow=1 streaming). The preset previously omitted this path, returning
403 at runtime for any log request. sockguard's startup validator also
requires insecure_allow_read_exfiltration: true when a config allows the
logs endpoint β without it the server refuses to start.
- Add GET /containers/*/logs rule to app/configs/lookout.yaml
- Set insecure_allow_read_exfiltration: true with security-tradeoff comment
- Mirror both changes to examples/compose/lookout/sockguard.yaml
- Update header comment to reflect that logs are now allowed
The compose example set LOOKOUT_DOCKER_SOCKET which is not a variable lookout reads. lookout reads DOCKER_SOCKET (confirmed in internal/config/config.go:143). With the wrong var name lookout fell back to auto-detection, found no socket (raw /var/run/docker.sock is not mounted), and failed to connect to sockguard at runtime.
β¦exec preset sockguard's startup validator (bodyInspectionConfiguredForEndpoint) only considers exec body-inspected when AllowedCommands is non-empty. With allow_root_user: true and no AllowedCommands the server refused to start: "rules allow body-sensitive write endpoints without request body inspection". - Add insecure_allow_body_blind_writes: true with security comment explaining the interactive-session tradeoff vs. the pinned-command pattern - Add insecure_allow_read_exfiltration: true since the exec preset should also support lookout's GetContainerLogs() like the base lookout preset - Add GET /containers/*/logs rule to match the base preset - Operator guidance: use drydock-with-selfupdate.yaml pattern (allowed_commands list) when the command set is known and pinnable
β¦nd gitlab-runner Both presets allowed exec endpoints without AllowedCommands and allowed GET /containers/*/logs and POST /containers/*/attach without the insecure_allow_read_exfiltration flag. sockguard's BuildChain validator would refuse to start the server with either config. - Add insecure_allow_body_blind_writes: true β exec needs arbitrary job step commands, not a pinned allowed_commands list - Add insecure_allow_read_exfiltration: true β runner streams job output via logs and attach APIs - Add explanatory comments referencing the socket-access mitigation
β¦eAndCompileRules coverage TestPresetConfigsValidate only ran config.Load + config.Validate, which does not catch missing insecure_allow_* flags that cause the server to refuse startup (BuildChain = validateAndCompileRules β compileClientProfiles). The new test loads every preset from app/configs/ and runs validateAndCompileRules on each one β the same path the live server takes on startup. This closes the gap that let lookout-with-exec.yaml, github-actions-runner.yaml, and gitlab-runner.yaml ship broken.
β¨ feat(presets): lookout presets + drydock self-update variant (M2/M3/M7)
The lookout, lookout-with-exec, github-actions-runner, and gitlab-runner presets allow GET /containers/*/logs and set insecure_allow_* flags, but the docs still listed logs as denied and omitted the flags. A docβcode audit surfaced 12 discrepancies, each verified against the YAML rules. - π docs(lookout): move logs from DeniesβAllows; disclose insecure_allow_read_exfiltration - π docs(lookout-with-exec): disclose insecure_allow_body_blind_writes + inherited exfil flag - π docs(runners): fix misleading "raw export" wording (logs/attach now stream); disclose both insecure flags - π fix(examples): correct lookout README + compose header that claimed "no insecure_allow_read_exfiltration"
β¦tup fix PR #99 shipped without CHANGELOG entries. Record the unreleased work: - π docs: lookout, lookout-with-exec, drydock-with-selfupdate presets (12 β 15) + lookout compose example under Added - π fix: github-actions-runner / gitlab-runner now load (missing insecure_allow_* flags) under Fixed
* π refactor(presets): rename lookout preset to Portwing Upstream agent renamed CodesWhat/lookout β CodesWhat/portwing, so the bundled preset follows. Pure rename, no rule changes. - π refactor(configs): lookout.yaml β portwing.yaml, lookout-with-exec.yaml β portwing-with-exec.yaml - π refactor(examples): examples/compose/lookout/ β examples/compose/portwing/ - π docs(presets): retitle Lookout sections, update agent URL, fix cross-references - π docs(readme,changelog): update preset list, compose-example list, and v1.4 changelog entry * π¨ style(branding): swap in new sockguard logo and regenerate favicons Replace the logo everywhere it ships and regenerate every derived icon from the new 1023x1023 source. - π¨ style(logo): new sockguard-logo.png at repo root, website/public, docs/public (all three kept byte-identical as before) - π¨ style(favicons): regenerate favicon.ico (16/32/48), favicon-96x96.png, apple-touch-icon.png, favicon.svg β transparency preserved - π¨ style(pwa): regenerate maskable web-app-manifest 192/512 (logo padded to safe zone, flattened on white) to match prior output - π§ config(layout): bump icon cache-buster ?v=20260408 β ?v=20260615 so returning visitors refetch * β¨ feat(banner): new dog startup banner with truecolor rendering Replace the old ASCII banner with the sockguard dog, and render it in full 24-bit colour on capable terminals with a clean monochrome fallback. - π¨ style(banner): swap the banner art for the block-glyph dog (ββββ), 53 cols - β¨ feat(banner): embed a 50-col half-block truecolor render (dog_color.ans), shown when the terminal advertises COLORTERM=truecolor/24bit - π fix(banner): count runes not bytes in artMaxWidth β the block glyphs are 3 bytes each, so len() overcounted ~3x and broke centering - π refactor(banner): centerArt takes an explicit width arg, so it centers both the rune-measured monochrome art and the ANSI-laden colour art - π§ͺ test(banner): measure width locally in the test helper instead of mutating package state * π¦ deps: refresh dev-tooling + sigstore-go for v1.4 soak - π¦ deps(go): bump sigstore/sigstore-go v1.2.0 β v1.2.1 (image-trust path; no behavior change) - π¦ deps(npm): Biome 2.4.16 β 2.5.0 - π¦ deps(npm): Tailwind 4.3.0 β 4.3.1; pin docs in lockstep with website - π¦ deps(npm): fumadocs 16.10.0 β 16.10.3, lucide-react 1.17 β 1.18, @radix-ui/react-slot 1.2 β 1.3 - π security(deps): regen lockfile from scratch so the postcss override resolves (npm audit: 0 vulnerabilities)
β¦ failover (#104) * β¨ feat(upstream): foundation for remote TCP+TLS upstreams with failover Adds the internal/upstream package (Endpoint, EndpointSpec, Resolver) β the single dial seam that replaces the hardcoded single-unix-socket assumption β and the config schema for it (upstream.endpoints[], upstream.failover, per-endpoint TLS). Consumers are not yet wired through it; that lands next. - β¨ feat(upstream): Endpoint + client-TLS-in-dialer, ordered failover Resolver, DOCKER_* env spec - β¨ feat(config): upstream.endpoints/failover schema + file-free ValidateSpec, register request_timeout default - π§ config(reload): upstream.endpoints/failover are reload-immutable; request_timeout stays mutable * β¨ feat(upstream): wire remote-upstream resolver through every proxy path Builds on the upstream foundation (6ac99df) by threading the shared *upstream.Resolver through the whole request stack so failover is coherent across the proxy, hijack, and side-channel inspects, then ships the docs, website, and examples for the feature. - π refactor(proxy): route reverse proxy, exec/attach hijack, ownership, visibility, client-ACL, and the filter exec-start inspector through the one shared resolver via *WithRoundTripper/*WithDialer constructors; legacy single-socket constructors stay as backward-compat wrappers - π refactor(serve): build the resolver once in newServeRuntime, reuse it across hot reloads, start its health loop in the serve lifecycle, and show the resolved endpoint label in the banner/startup log - β¨ feat(upstream): CheckReachable boots a failover set when β₯1 endpoint answers and fails fast when all are dark; legacy single socket keeps the precise not-found/permission fail-fast check - π fix(upstream): don't demote the active endpoint on request-scoped errors (client cancel / request_timeout) β only real reachability failures fail over - π fix(upstream): DOCKER_TLS_VERIFY with no DOCKER_CERT_PATH now builds a valid system-roots TLS endpoint instead of being rejected as plain TCP - π fix(upstream): gate demote's async re-probe to one goroutine per endpoint and bind it to the resolver lifetime; serialize setHealth's swap-and-notify - π fix(config): reject upstream.failover.health_interval "0s" (ambiguous with the default) and point operators at negative-to-disable / omit-for-default - π fix(cli): validate header shows configured endpoints, not the unused socket - π docs: new Remote Upstreams & Failover guide, configuration + env-var reference, README comparison/roadmap, and a runnable compose example - π§ͺ test: cover resolver pool tunings, CheckReachable, system-roots TLS, request-scoped no-demote, endpoints/failover immutability, and failover env vars
β¦-scheme - π¨ add inverted sockguard-logo-dark.png (force-added past the /*.png ignore, matching the existing logo) - π wrap the README logo in <picture> so it swaps to the dark variant under prefers-color-scheme: dark
β¦ count - π add '## [1.4.0-rc.1] - 2026-06-16' heading under the [Unreleased] stub; release-from-tag.yml's changelog gate requires a dated heading matching the pushed tag - π¨ website features.ts: 12 β 15 bundled presets (+ Portwing, Portwing with exec, Drydock with self-update) to match README/CHANGELOG/docs
* π¨ style(assets): add CodesWhat brand logo (ecosystem footer parity) * π¨ style(readme): embed Sigstore + GoReleaser icons (dropped from simple-icons), CodesWhat logo footer * π¨ style(readme): trim library badges, add AI-tools row, standards below Built With, ecosystem cross-link table
dev/v1.4 already carried most of the npm-minor group; this folds only the lagging deltas dependabot opened against frozen main in #102: - @biomejs/biome ^2.4.16 β ^2.5.0 - turbo ^2.9.17 β ^2.9.18 - fumadocs-core/fumadocs-ui ^16.9.3 β ^16.10.3, fumadocs-mdx ^15.0.11 β ^15.0.12 - lucide-react ^1.17.0 β ^1.18.0 - tailwindcss + @tailwindcss/postcss ^4.3.0 β ^4.3.1 (website) - @types/node ^25.9.2 β ^25.9.3 (docs + website) Lockfile regenerated and deduped (clean-env).
β¦ipped versions fumadocs from-version (16.9.3 not 16.10.0), drop the @radix-ui/react-slot 1.2β1.3 claim (tree is ^1.2.4, never bumped), add the turbo 2.9.17β2.9.18 that actually landed via the npm-minor fold (#105).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
β¦flow release-cut auto-computes only stable semver, so rc tags (v1.4.0-rc.1) fell back to hand-cutting β the one rough edge vs the drydock release flow. - Add an optional `release_tag` workflow_dispatch input (drydock-style): when supplied, cut that exact tag (validated format + not-already-exists + non-empty CHANGELOG entry); blank still auto-computes the next stable version. Fully backward-compatible. - Fix RELEASING.md: tags are unsigned annotated bot tags (`git tag -a`), not signed β provenance is cosign keyless + SLSA in release-from-tag, not a git-tag signature. Document the rc cut path.
Go Lint was nondeterministic β golangci-lint-action ran unpinned, so it
floated to a newer golangci-lint whose staticcheck regressed SA5011 and
false-positived "possible nil pointer dereference" on `if x == nil {
t.Fatal(...) }` guards in serve_reload_test.go / serve_policy_bundle_test.go
(t.Fatal ends the test via Goexit; the deref below is unreachable). Same
SHA passed an earlier run and failed the next. Pin to v2.12.2 β the local
lefthook go-lint version β so CI lint matches local and is reproducible.
β¦5011)
CI's golangci-lint flags SA5011 "possible nil pointer dereference" on the
`if x == nil { t.Fatal(...) }` guards in serve_reload_test.go and
serve_policy_bundle_test.go: its staticcheck doesn't model t.Fatal's Goexit
termination, so it thinks the deref on the next line can still see nil. The
local linter (identical v2.12.2 + Go 1.26.4) doesn't flag it, which is what
made Go Lint nondeterministic across environments. An explicit `return`
after each t.Fatal makes the non-nil guarantee explicit in control flow, so
every staticcheck build accepts it. Together with the v2.12.2 pin in
ci-verify, Go Lint is now reproducible localβCI.
β¦te returns
Root-cause fix for the nondeterministic Go Lint. CI's golangci-lint binary
flags SA5011 "possible nil pointer dereference" on every
`if x == nil { t.Fatal(...) }; x.field` guard in test files β it doesn't
model t.Fatal's runtime.Goexit termination β while the identical local
v2.12.2 + Go 1.26.4 reports zero. golangci's max-same-issues meant each run
surfaced only a few sites (serve_reload, serve_policy_bundle, then
imagefetch/bundle_keyless, ...), so the per-site `return` approach from
c07faba was whack-a-mole.
Exclude SA5011 only in `_test.go` (alongside the existing errcheck/gosec/
bodyclose test exclusions) β kills the whole false-positive class
deterministically and keeps SA5011 active on production code. Revert the
three band-aid returns now that the class is handled at config level.
biggest-littlest
approved these changes
Jun 16, 2026
biggest-littlest
left a comment
Member
There was a problem hiding this comment.
Approving the v1.4.0-rc.1 release merge (dev/v1.4 β main). All required CI green; Go Lint now deterministic (SA5011 test-file exclusion) and the request-ID entropy flake cleared on re-run.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Starts the v1.4 release train: merges the dev/v1.4 soak branch into main so the
v1.4.0-rc.1tag can be cut from main (the established release flow β cf. #88dev/v1.3 β main). main stays at the v1.3.0 GA contract; this is the rc.1 cut for soak, not GA promotion (README "latest" prose flips at GA).Headline changes (see CHANGELOG
[1.4.0-rc.1])upstream.endpoints[]) β mTLS dialer across reverse-proxy, exec/attach hijack, and inspect side-channels; per-endpoint TLS + health probes.ContainerSpec.Privilegesseccomp/AppArmor confinement rails β completes parity with container-create.SecurityOptSELinux + system-paths directives are policy-evaluable (label=disable, label overrides, systempaths=unconfined incl. theMaskedPaths: []client-side vector).No source version bump (build-injected). Chart stays at 1.3.0 for the rc per the soak convention (bumps at GA). After merge,
v1.4.0-rc.1gets tagged from main β release-from-tag.yml builds + publishes ghcr/dockerhub/quay + cosign-signs the image.